use std::ffi::CString;
use std::fs::File;
use std::io::Write;
use std::os::raw::c_void;

use ash::vk::{QueueFlags, QueueFamilyProperties};
use ash::{vk, Entry};
use chrono::Local;

use super::vk_struct::{VkRequiredQueue, VkSupportedQueue, QueueType, debug_utils, VkSurface, VkFamilyQueue};
use super::vk_utils::utils_time::get_formatted_time;
use crate::vulkan::vk_utils::utils_extension;
use crate::{LOG_FILE, VK_CHECK, VK_CHECK_UNSAFE, VK_LOGD, VK_LOGE, VK_LOGP, VK_LOGV};

use super::VkConfig;
use super::vk_utils::utils_ffi::*;

impl VkConfig {
    /// Vulkan 配置
    pub fn new() -> VkConfig {
        VkConfig {
            application_name                : CString::new("VkApplication").unwrap(),
            engine_name                     : CString::new("VkEngine").unwrap(),
            required_layer_names            : vec![],
            required_extension_names        : vec![],
            required_device_extension_names : vec![],

            supported_queues                : vec![],
            required_queues                 : vec![],
            device_queue_num                : 0, 
            
            // Debug Utils Config
            use_debug_utils                 : true,
            message_severity_flags          : vk::DebugUtilsMessageSeverityFlagsEXT::empty(),
            message_type_flags              : vk::DebugUtilsMessageTypeFlagsEXT::empty(),

            verbose_log                     : true,
            use_ray_tracing                 : false
        }
    }

    /// 增加一条Layer
    pub fn add_required_layer(&mut self, layer_name: &'static str) {
        self.required_layer_names.push(CString::new(layer_name).unwrap())
    }

    pub fn add_required_extension(&mut self, extension_name: &'static str) {
        self.required_extension_names.push(CString::new(extension_name).unwrap())
    }

    pub fn add_required_device_extension(&mut self, device_extension_name: &'static str) {
        self.required_device_extension_names.push(CString::new(device_extension_name).unwrap())
    }

    pub fn add_required_queue(&mut self, required_queue: VkRequiredQueue) {
        self.required_queues.push(required_queue);
    }

    /// 根据部分配置生成额外的信息
    /// 根据平台生成对应平台信息
    pub fn gen_more_info(&mut self) {
        // Debug extension
        if self.use_debug_utils {
            self.add_required_layer("VK_LAYER_KHRONOS_validation");
            self.add_required_extension("VK_EXT_debug_utils");
            if self.verbose_log {
                self.message_severity_flags |=  vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
            }
        }
        
        // Surface extension
        self.add_required_extension("VK_KHR_surface");
        self.add_required_extension(
            #[cfg(all(windows))]
            "VK_KHR_win32_surface",
            #[cfg(target_os = "macos")]
            "VK_MVK_macos_surface",
            #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
            "VK_KHR_xlib_surface"
        );
        self.add_required_device_extension("VK_KHR_swapchain");
        #[cfg(target_os = "macos")]
        self.add_required_device_extension("VK_KHR_portability_subset");

        // Macos extra extension
        #[cfg(target_os = "macos")]
        self.add_required_extension("VK_KHR_portability_enumeration");

        // Queue
        self.add_required_queue(VkRequiredQueue{ queue_type: QueueType::GTC,    queue_flag: QueueFlags::GRAPHICS | QueueFlags::COMPUTE | QueueFlags::TRANSFER , queue_count: 1} );
        self.add_required_queue(VkRequiredQueue{ queue_type: QueueType::C,      queue_flag: QueueFlags::COMPUTE,                                                queue_count: 1} );
        self.add_required_queue(VkRequiredQueue{ queue_type: QueueType::T,      queue_flag: QueueFlags::TRANSFER,                                               queue_count: 1} );
    }

    pub fn get_application_info(&self) -> vk::ApplicationInfo {
        vk::ApplicationInfo {
            s_type                          : vk::StructureType::APPLICATION_INFO,
            p_next                          : std::ptr::null(),
            p_application_name              : self.application_name.as_ptr(),
            p_engine_name                   : self.engine_name.as_ptr(),
            api_version                     : vk::make_api_version(0, 1, 3, 0),

            ..Default::default()
            // application_version          : ,
            // engine_version               : ,
        }
    }

    /// as_ptr前面的量必须生命周期在函数内, 如果是临时变量则会不生效
    /// ```
    /// Right:
    ///     let maintain_life = vk_config.get_required_layer_names()
    ///     maintain_life.as_ptr()
    /// 
    /// Wrong:
    ///     vk_config.get_required_layer_names().as_ptr()
    /// ```
    pub fn get_required_layer_names(&self) -> Vec<*const i8> {
        self.required_layer_names
            .iter()
            .map(|layer_name| layer_name.as_ptr())
            .collect()
    } 

    pub fn get_required_extension_names(&self) -> Vec<*const i8> {
        self.required_extension_names
            .iter()
            .map(|extension_name| extension_name.as_ptr())
            .collect()
    } 

    pub fn get_required_device_extension_names(&self) -> Vec<*const i8> {
        self.required_device_extension_names
            .iter()
            .map(|extension_name| extension_name.as_ptr())
            .collect()
    } 

    /// 直接在这个函数内初始化所有变量不现实
    /// 1. application_info会导致Dangling Ref，外面初始化的时候ptr失效
    /// 2. 类似的required_layer_names_ptr也是悬垂引用
    /// 3. 如果需要实现直接在这个函数里面初始化所有值，需要利用Struct存这些值强行延长生命周期，不划算，下面是方法
    /// ```
    /// Solution:
    ///     struct {
    ///         ...
    ///         required_layer_names_ptr    : Vec<*const i8>
    ///         application_info            : ApplicationInfo
    ///     }
    /// 
    ///     使用时
    ///     &vk_config.application_info
    /// ```
    pub fn get_instance_ci(&self) -> vk::InstanceCreateInfo {
        vk::InstanceCreateInfo {
            s_type                          : vk::StructureType::INSTANCE_CREATE_INFO,
            p_next                          : std::ptr::null(),
            
            #[cfg(target_os = "macos")]
            flags                           : vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR,

            ..Default::default()
        }
    }

    pub fn get_device_ci(&self) -> vk::DeviceCreateInfo {
        vk::DeviceCreateInfo {
            s_type                          : vk::StructureType::DEVICE_CREATE_INFO,
            p_next                          : std::ptr::null(),
            
            // #[cfg(target_os = "macos")]
            // pub const DEVICE_EXTENSIONS: [&'static str; 2] = ["VK_KHR_swapchain", "VK_KHR_portability_subset"];
            // #[cfg(target_os = "macos")]
            // flags                           : vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR,

            ..Default::default()
        }
    }
    
    pub fn get_debug_utils_ci(&self) -> vk::DebugUtilsMessengerCreateInfoEXT {
        vk::DebugUtilsMessengerCreateInfoEXT {
            message_severity                : self.message_severity_flags,
            message_type                    : self.message_type_flags,
            pfn_user_callback               : Some(debug_utils::vk_debug_utils_callback),

            ..Default::default()
        }
    }

    pub fn check_enumerate_instance_version(&self, vk_entry: &Entry) {
        if let Some(instance_version) = VK_CHECK!(vk_entry.try_enumerate_instance_version()) {
            match instance_version {
                // Vulkan 1.1+
                Some(version) => {      
                    VK_LOGV!("vk_entry.try_enumerate_instance_version()");
                    VK_LOGV!("    {} {} {} {}", vk::api_version_variant(version), vk::api_version_major(version), vk::api_version_minor(version), vk::api_version_patch(version));
                },
                // Vulkan 1.0
                None => {},
            }
        }
    }

    pub fn check_required_layer(&self, instance_layer_properties: Vec<vk::LayerProperties>) {
        // Debug Log
        if self.verbose_log {
            VK_LOGV!("instance_layer_properties");
            for properties in &instance_layer_properties {
                let layer_name      = i8_2_str(&properties.layer_name);
                let description     = i8_2_str(&properties.description);
                VK_LOGV!("    {:50} {:70} v.{}", layer_name, description, properties.implementation_version);
            }

            VK_LOGV!("required_layer_names: {}", self.required_layer_names.len());
            for layer_name in &self.required_layer_names {
                let layer_name_str = i8_ptr_2_str(&layer_name.as_ptr());
                VK_LOGV!("    {:50}", layer_name_str);
            }
        }

        // 筛选出不支持的layer name
        let unsupported_layer_names: Vec<String> = self.required_layer_names
            .iter()
            .map(|required_layer_name| String::from_utf8(required_layer_name.to_bytes().to_vec()).unwrap())
            .filter(|required_layer_name|
                !instance_layer_properties
                    .iter()
                    .any(|supported_layer_properties|
                        i8_2_string(&supported_layer_properties.layer_name)
                            .eq(required_layer_name)
                    )
            ).collect();

        if unsupported_layer_names.len() > 0 {
            for unsupported_layer_name in unsupported_layer_names {
                VK_LOGE!("Unsupport layer name {:50}", unsupported_layer_name);
            }
            VK_LOGP!("Not All layer Supported");
        }
    }

    /// extension_properties是API Query出来的List
    /// 和required_extension_names输出对比
    pub fn display_extension(&self, extension_properties: &Vec<vk::ExtensionProperties>) {
        utils_extension::display_extension(
            &self.required_extension_names, 
            extension_properties, 
            "instance_extension_properties", 
            "required_extension_names");
    }
    
    /// device_extension_properties是API Query出来的List
    /// 和required_device_extension_names输出对比
    pub fn display_device_extension(&self, device_extension_properties: &Vec<vk::ExtensionProperties>) {
        utils_extension::display_extension(
            &self.required_device_extension_names, 
            device_extension_properties, 
            "device_extension_properties", 
            "required_device_extension_names");
    }

    /// extension_properties是API Query出来的List
    /// 筛选required_extension_names是不是都支持
    pub fn check_extension_properties_supported(&self, extension_properties: &Vec<vk::ExtensionProperties>) {
        let unsupported_extension_names = utils_extension::get_unsupported_extension(&self.required_extension_names, extension_properties);
        // 根据长度判断
        if unsupported_extension_names.len() > 0 {
            for unsupported_extension_name in unsupported_extension_names {
                VK_LOGE!("Unsupport extension name {:50}", unsupported_extension_name);
            }
            VK_LOGP!("Not All extension Supported");
        }
    }

    /// device_extension_properties是API Query出来的List
    /// 筛选required_device_extension_names是不是都支持
    pub fn check_device_extension_properties_supported(&self, device_extension_properties: &Vec<vk::ExtensionProperties>) -> bool {
        let unsupported_extension_names = utils_extension::get_unsupported_extension(&self.required_device_extension_names, device_extension_properties);
        // 根据长度判断
        if unsupported_extension_names.len() > 0 {
            for unsupported_extension_name in unsupported_extension_names {
                VK_LOGE!("Unsupport device extension name {:50}", unsupported_extension_name);
            }
            return false
        }
        true
    }

    pub fn check_required_extension(&self, instance_extension_properties: Vec<vk::ExtensionProperties>) {
        // Debug Log
        if self.verbose_log {
            VK_LOGV!("instance_extension_properties");
            self.display_extension(&instance_extension_properties);
        }
        // 筛选出不支持的extension name
        self.check_extension_properties_supported(&instance_extension_properties);
    }

    pub fn check_required_device_extension(&self, device_extension_properties: Vec<vk::ExtensionProperties>) -> bool {
        // Debug Log
        if self.verbose_log {
            VK_LOGV!("device_supported_extension_properties");
            self.display_device_extension(&device_extension_properties);
        }
        // 筛选出不支持的extension name
        self.check_device_extension_properties_supported(&device_extension_properties)
    }

    /// 根据需要的信息弄出来对应的
    /// 找到Physical Device里面的适合的queue
    pub fn query_required_queue(
        &self,
        physical_device_queue_family_properties: &Vec<QueueFamilyProperties>
    ) -> Vec<VkSupportedQueue> {
        let mut queue = vec![];
        let mut queue_counters = vec![0; physical_device_queue_family_properties.len()];

        for required_queue in &self.required_queues {
            for queue_family_index in 0..physical_device_queue_family_properties.len() {
                let queue_counter = queue_counters[queue_family_index];
                let queue_family_property = physical_device_queue_family_properties[queue_family_index];

                if queue_family_property.queue_count - queue_counter > 0 && queue_family_property.queue_flags.contains(required_queue.queue_flag) {
                    queue.push(VkSupportedQueue { 
                        queue_type      : required_queue.queue_type,
                        family_index    : queue_family_index as u32,
                        queue_index     : queue_counter,
                        queue_flag      : required_queue.queue_flag,
                        queue_priority  : 1.0f32
                    });
                    queue_counters[queue_family_index] = queue_counters[queue_family_index] + 1;
                    break;
                }
            }
        }

        queue
    }

    /// 很关键的一个Vulkan的设计模式，链式查找
    /// 如果我们需要查找这个设备的几个不同的Properties，肯定没法动态的放几个进来或者拿几个出去
    /// 此时p_next的设计就出现了
    /// 要拉取基础信息 get_physical_device_properties 可能已经满足要求了
    /// 而额外的Properties需要使用get_physical_device_properties2
    /// 逻辑如下
    /// ```
    /// let header          = vk::PhysicalDeviceProperties2     为链表头
    /// property1           = vk::SomePropertiesStructure1      为第一个想查找的结构
    /// header.p_next       = property1                         加入链表
    /// property2           = vk::SomePropertiesStructure2      为第二个想查找的结构
    /// 
    /// property1.p_next    = property2                         加入链表
    /// vk_instance.get_physical_device_properties2(*vk_physical_device, &mut header) 链式查找
    /// property1和property2的信息都有了
    /// ```
    /// 可是PhysicalDeviceProperties2为什么需要PhysicalDeviceProperties呢，还不知道
    pub fn check_physical_device(&mut self, vk_instance: &ash::Instance, vk_surface: &VkSurface, vk_physical_device: &vk::PhysicalDevice) -> bool {
        // Check Properties
        let device_properties = unsafe {vk_instance.get_physical_device_properties(*vk_physical_device)};
        VK_LOGD!("Check Device: {:?}", unsafe{ std::ffi::CStr::from_ptr(device_properties.device_name.as_ptr()) });

        // todo!("把Properties也可以加到Config里面");

        let mut fragment_shading_rate_property  = vk::PhysicalDeviceFragmentShadingRatePropertiesKHR::default().clone(); // property1
        let mut protability_subset_property     = vk::PhysicalDevicePortabilitySubsetPropertiesKHR::default().clone(); // property2
        protability_subset_property.p_next      = &mut fragment_shading_rate_property as *mut vk::PhysicalDeviceFragmentShadingRatePropertiesKHR as *mut c_void;

        let mut device_properties2 = vk::PhysicalDeviceProperties2 {
            s_type          : vk::StructureType::PHYSICAL_DEVICE_PROPERTIES_2_KHR,
            p_next          : &mut protability_subset_property as *mut vk::PhysicalDevicePortabilitySubsetPropertiesKHR as *mut c_void,
            properties      : device_properties
        };
        unsafe {vk_instance.get_physical_device_properties2(*vk_physical_device, &mut device_properties2);};

        // Check Device Extension Support
        let device_supported_extension_properties = match VK_CHECK_UNSAFE!(vk_instance.enumerate_device_extension_properties(*vk_physical_device)) {
            Some(inner_value) => {inner_value},
            None => { VK_LOGP!("Failed to get device extension properties!"); }
        };
        if !self.check_required_device_extension(device_supported_extension_properties) {
            return false
        }

        // Check Swapchain Info
        let swapchain_support = vk_surface.query_device_swapchain_support(vk_physical_device);
        if self.verbose_log {
            VK_LOGV!("swapchain_support");
            swapchain_support.debug_print();
        }
        if !swapchain_support.is_valid() {
            return false
        }

        // Check family queue
        let physical_device_queue_family_properties = unsafe { vk_instance.get_physical_device_queue_family_properties(*vk_physical_device)};
        if self.verbose_log {
            VK_LOGV!("physical_device_queue_family_properties");
            for queue_family_property in &physical_device_queue_family_properties {
                VK_LOGV!("    {:?}", queue_family_property);
            }
        }
        
        let supported_queues = self.query_required_queue(&physical_device_queue_family_properties);
        if self.verbose_log {
            VK_LOGV!("query_required_queue");
            for supported_queue in &supported_queues {
                VK_LOGV!("    family_index({}) queue_index({})", supported_queue.family_index, supported_queue.queue_index);
            }
        }
        if supported_queues.len() != self.required_queues.len() {
            return false
        }
        // Check GTC Queue

        // Set Queue Info to Config
        self.device_queue_num = physical_device_queue_family_properties.len() as u32;
        self.supported_queues = supported_queues;

        true
    }

    /// 整合Queue Create Info<br>
    /// vk_config.supported_queues里面存了每条Queue对应的family index和queue index<br>
    /// 但是QueueCreateInfo在Create的时候最好不要有重复的family index，这边需要整合一遍到family index统计起来
    pub fn get_merged_family_queues(&self) -> Vec<VkFamilyQueue> {
        let mut family_queues = vec![];
        // 用index初始化family queue
        for family_queue_index in 0..self.device_queue_num {
            family_queues.push(VkFamilyQueue::new(family_queue_index))
        }
        // 将supported_queue存到对应的family里面去
        for supported_queue in &self.supported_queues {
            family_queues[supported_queue.family_index as usize].add_queue(supported_queue);
        }
        if self.verbose_log {
            VK_LOGV!("family_queues");
            for family_queue in &family_queues {
                VK_LOGV!("    {:?}", family_queue);
            }
        }

        family_queues
    }
}